/*
 * Copyright (C) 2010 Michael Pardo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.activeharmony.sample;

import static org.junit.Assert.assertEquals;

import com.activeharmony.sample.slice.Details;

import com.activeharmony.query.Delete;
import com.activeharmony.query.From;
import com.activeharmony.query.Select;

import org.junit.Test;

import java.util.List;

/**
 * CountTest.
 */
public class CountTest extends ExampleOhosTest {
    private static String str = "Andrew";

    private void cleanTable() {
        new Delete().from(Details.class).execute();
    }

    private void populateTable() {
        Details m1 = new Details();
        m1.setName(str);
        m1.setAge("12");
        Details m2 = new Details();
        m2.setName(str);
        m2.setAge("12");
        Details m3 = new Details();
        m3.setName("Tony");
        m3.setAge("11");
        m1.save();
        m2.save();
        m3.save();
    }

    /**
     * Should be a simple count for the entire table.
     */
    @Test
    public void testCountTableSql() {
        final String expected = "SELECT COUNT(*) FROM Details";

        String actual = new Select().from(Details.class).toCountSql();

        assertEquals(expected, actual);
    }

    /**
     * Should be a count with the specified where-clause.
     */
    @Test
    public void testCountWhereClauseSql() {
        final String expected = "SELECT COUNT(*) FROM Details WHERE name = ?";

        String actual = new Select().from(Details.class).where("name = ?", "Tony").toCountSql();

        assertEquals(expected, actual);
    }

    /**
     * Shouldn't include <i>order by</i> as it has no influence on the result of <i>count</i> and
     * should improve performance.
     */
    @Test
    public void testCountOrderBySql() {
        final String expected = "SELECT COUNT(*) FROM Details WHERE name <> ? GROUP BY age";

        String actual = new Select().from(Details.class)
            .where("name <> ?", 0)
            .orderBy("name")
            .groupBy("age")
            .toCountSql();

        assertEquals(expected, actual);
    }

    /**
     * Should return the same count as there are entries in the result set/table.
     */
    @Test
    public void testCountTable() {
        cleanTable();
        populateTable();

        From from = new Select().from(Details.class);

        final List<Details> list = from.execute();
        final int count = from.count();

        assertEquals(3, count);
        assertEquals(list.size(), count);
    }

    /**
     * Should return the same count as there are entries in the result set if the where-clause
     * matches several entries.
     */
    @Test
    public void testCountWhereClause() {
        cleanTable();
        populateTable();

        From from = new Select().from(Details.class).where("name = ?", str);

        final List<Details> list = from.execute();
        final int count = from.count();

        assertEquals(2, count);
        assertEquals(list.size(), count);
    }

    /**
     * Should return the same count as there are entries in the result set if the where-clause
     * matches zero entries.
     */
    @Test
    public void testCountEmptyResult() {
        cleanTable();
        populateTable();

        From from = new Select().from(Details.class).where("name = ?", "Test");

        final List<Details> list = from.execute();
        final int count = from.count();

        assertEquals(0, count);
        assertEquals(list.size(), count);
    }

    /**
     * Should not change the result if order by is used.
     */
    @Test
    public void testCountOrderBy() {
        cleanTable();
        populateTable();

        From from = new Select().from(Details.class).where("name = ?", str).orderBy("name ASC");

        final List<Details> list = from.execute();
        final int count = from.count();

        assertEquals(2, count);
        assertEquals(list.size(), count);
    }

    /**
     * Should return the total number of rows, even if the rows are grouped. May seem weird, just
     * test it in an SQL explorer.
     */
    @Test
    public void testCountGroupBy() {
        cleanTable();
        populateTable();

        From from = new Select().from(Details.class).groupBy("age").having("age = 12");

        final List<Details> list = from.execute();
        final int count = from.count();

        assertEquals(2, count);
        assertEquals(1, list.size());
    }
}
